package commRedisExchange

import (
	"encoding/json"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedis"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"github.com/go-redis/redis"
	"strings"
	"time"
)

const (
	keyData = "fox-edge:service:exchange:data"
)

func SaveConfigValue(serviceType, serviceName, configName string, configValue map[string]interface{}) error {
	serviceKey := encodeServiceKey(serviceType, serviceName, configName)

	jsn, err := encodeJson(configValue)
	if err != nil {
		return err
	}

	_, err = commRedis.Client.HSet(keyData, serviceKey, jsn).Result()
	if err != nil {
		return err
	}

	return nil
}

func ExistConfigValue(serviceType, serviceName, configName string) (bool, error) {
	_, _, err := ReadConfigValue(serviceType, serviceName, configName)
	if err != nil && err != redis.Nil {
		return false, err
	}

	return err == nil, nil
}

// ReadConfigValue 读取配置数值
// 说明：对应的serviceKey在首次读取的时候，可能在redis不存在，所以要用下面的方式去判定真正的读取失败
//
//	if err != nil && err != redis.Nil {
//	   return err
//	}
func ReadConfigValue(serviceType, serviceName, configName string) (value map[string]interface{}, updateTime int64, err error) {
	// 拦截可能产生的异常
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()

	serviceKey := encodeServiceKey(serviceType, serviceName, configName)

	jsn, err := commRedis.Client.HGet(keyData, serviceKey).Result()
	if err != nil {
		return nil, 0, err
	}

	value, updateTime = decodeJson(jsn)

	return value, updateTime, nil
}

func FindConfigValues(finder func(data map[string]interface{}) bool) ([]map[string]interface{}, error) {
	values, err := ReadConfigValues()
	if err != nil {
		return nil, err
	}

	list := make([]map[string]interface{}, 0)
	for _, v := range values {
		if finder(v) {
			list = append(list, v)
		}
	}

	return list, nil
}

func ReadConfigValues() (list []map[string]interface{}, err error) {
	// 拦截可能产生的异常
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()

	key2jsn, err := commRedis.Client.HGetAll(keyData).Result()
	if err != nil {
		return nil, err
	}

	list = make([]map[string]interface{}, 0)
	for key, jsn := range key2jsn {
		value := make(map[string]interface{})
		json.Unmarshal([]byte(jsn), &value)

		serviceType, serviceName, configName := decodeServiceKey(key)
		if serviceType == "" {
			continue
		}

		data := make(map[string]interface{})
		data["serviceType"] = serviceType
		data["serviceName"] = serviceName
		data["configName"] = configName
		data["updateTime"] = Map.GetInt64(value, "updateTime", 0)
		data["configValue"] = Map.GetMap(value, "configValue", make(map[string]interface{}))

		list = append(list, data)
	}

	return list, err
}

func RemoveConfigValue(serviceType, serviceName, configName string) error {
	serviceKey := encodeServiceKey(serviceType, serviceName, configName)

	_, err := commRedis.Client.HDel(keyData, serviceKey).Result()
	if err != nil {
		return err
	}

	return nil
}

func decodeJson(jsn string) (map[string]interface{}, int64) {
	value := make(map[string]interface{})
	err := json.Unmarshal([]byte(jsn), &value)
	if err != nil {
		return nil, 0
	}

	updateTime := Map.GetInt64(value, "updateTime", 0)
	configValue := Map.GetMap(value, "configValue", make(map[string]interface{}))

	return configValue, updateTime
}

func encodeJson(configValue map[string]interface{}) (string, error) {
	value := make(map[string]interface{})
	value["updateTime"] = time.Now().UnixMilli()
	value["configValue"] = configValue

	code, err := json.Marshal(value)
	if err != nil {
		return "", err
	}
	jsn := string(code)

	return jsn, nil
}

func encodeServiceKey(serviceType, serviceName, configName string) string {
	return "\"" + serviceType + ":" + serviceName + ":" + configName + "\""
}

func decodeServiceKey(serviceKey string) (serviceType, serviceName, configName string) {
	if len(serviceKey) < 4 {
		return "", "", ""
	}
	serviceKey = serviceKey[1 : len(serviceKey)-1]

	items := strings.Split(serviceKey, ":")
	if len(items) != 3 {
		return "", "", ""
	}

	return items[0], items[1], items[2]
}
